package ch.ethz.fcl.metrofont;

import java.awt.Color;
import java.util.ArrayList;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

public class MetroFont {
	private ArrayList<TextureFont> fonts = new ArrayList<TextureFont>();
	private TextureAtlas atlas = null;

	private int defaultFS = 30;

	private int atlasSize = 512;

	private FontMarkup defaultFM = null;

	public MetroFont() {
		defaultFM = new FontMarkup(this.defaultFS);
		atlas = new TextureAtlas(atlasSize, atlasSize, 1);

		// String str = "";
		// for (int i = 0; i < 100; i++)
		// str += (char) i;
		// cache(str);
		// GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
	}

	public MetroFont(String font, int size) {
		defaultFS = size;
		defaultFM = new FontMarkup(font, defaultFS);
		atlas = new TextureAtlas(atlasSize, atlasSize, 1);
	}

	public MetroFont(String font, int size, Color fontColor,
			Color backgroundColor) {
		defaultFS = size;
		defaultFM = new FontMarkup(font, defaultFS, fontColor, backgroundColor);
		atlas = new TextureAtlas(atlasSize, atlasSize, 1);
	}

	public float getLength(String str, float fontSize) {
		cache(str);
		Pen pen = new Pen(0, 0, fontSize);
		float startX = pen.getX();
		TextureFont font = getFont(defaultFM);
		if (pen.getFontSize() == 0)
			pen.setFontSize(defaultFS);

		font.display(atlas, str, pen, false);
		return pen.getX() - startX;
	}

	public void display(String str, Pen pen) {
		cache(str);
		TextureFont font = getFont(defaultFM);

		if (pen.getFontSize() == 0)
			pen.setFontSize(defaultFS);

		GL11.glEnable(GL11.GL_TEXTURE_2D);
		atlas.getTexture().bind();
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S,
				GL12.GL_CLAMP_TO_EDGE);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T,
				GL12.GL_CLAMP_TO_EDGE);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER,
				GL11.GL_LINEAR);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
				GL11.GL_LINEAR);

		font.display(atlas, str, pen, true);

		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
	}

	private void cache(String str) {
		cacheGlyphs(defaultFM, str);
		atlas.upload();
	}

	private void cacheGlyphs(FontMarkup markup, String msg) {
		TextureFont font = getFont(markup);
		if (font == null) {
			font = new TextureFont(markup);
			addFont(font);
		}
		font.cacheGlyphs(atlas, msg);
	}

	private void addFont(TextureFont font) {
		fonts.add(font);
	}

	private TextureFont getFont(FontMarkup markup) {
		for (int i = 0; i < fonts.size(); i++)
			if (fonts.get(i).match(markup))
				return fonts.get(i);
		return null;
	}

	public TextureAtlas getAtlas() {
		return atlas;
	}

	public void setFontColor(Color color) {
		defaultFM.setFontColor(color);
	}

	public void setFontSize(int size) {
		defaultFM.setFontSize(size);
	}

	public void setFontName(String name) {
		defaultFM.setFontName(name);
	}
}
